const CryptoJS = require('crypto-js');

const KEY_SIZE_BIT = 256;
const TAG_LENGTH_BIT = 256;
const IV_LENGTH_BYTE = 16;
const KEY_LENGTH_BYTE = 32;

/**
 * 生成一个随机的AES加密密钥。
 *
 * @return 以字符串形式返回生成的密钥。
 */
function generateKey() {
	return crypto.randomBytes(KEY_LENGTH_BYTE).toString('base64');
}

/**
 * 生成一个随机的AES初始化向量，并以Base64编码的字符串形式返回。
 *
 * @return 以字符串形式返回生成的初始化向量。
 */
function generateIV() {
	return crypto.randomBytes(IV_LENGTH_BYTE).toString('base64');
}


/**
 * 使用给定的密钥和初始化向量加密给定的明文。
 *
 * @param plaintext 要加密的明文。
 * @param key       加密使用的密钥。
 * @param iv        加密使用的初始化向量。
 * @return 以Base64编码的字符串形式返回加密后的密文。
 * @throws Exception 如果在加密过程中发生错误。
 */
function encrypt(plaintext, key, iv) {
	if (!plaintext || !key || !iv) {
		throw new Error('plaintext, key, iv cannot be null.');
	}
	// console.info(
	// 	`\n\n-------- CryptoJS Info Begin --------\n\n`,
	// 	CryptoJS,
	// 	`\n\n-------- CryptoJS Info end   --------\n\n`
	// );
	// CryptoJS supports the following modes:
	// CBC(the default )
	// CFB
	// CTR
	// OFB
	// ECB

	const encrypted = CryptoJS.AES.encrypt(plaintext, key, {
		iv: iv,
	});

	return encrypted.toString();
}

/**
 * 使用给定的密钥和初始化向量解密给定的密文。
 *
 * @param ciphertext 要解密的密文。
 * @param key        解密使用的密钥。
 * @param iv         解密使用的初始化向量。
 * @return 解密后的明文。
 * @throws Exception 如果在解密过程中发生错误。
 */
function decrypt(ciphertext, key, iv) {
	if (!ciphertext) {
		throw new Error('Ciphertext cannot be null or empty.');
	}
	if (!key) {
		throw new Error('Key cannot be null or empty.');
	}
	if (!iv) {
		throw new Error('IV cannot be null or empty.');
	}
	const decrypted = CryptoJS.AES.decrypt(ciphertext, key, {
		iv: iv,
	});
	// decrypted.toString(CryptoJS.enc.Utf8)
	return decrypted.toString(CryptoJS.enc.Utf8);
}

module.exports = {
	generateKey,
	generateIV,
	encrypt,
	decrypt
};
